import java.awt.Graphics;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.PriorityQueue;

import javax.swing.ImageIcon;

public class Map implements Drawable{

	private BackgroundTile[][] bgGrid;
	private Tile[][] fgGrid;
	private int cols, rows;
	//each map will have its own set of NPCs
	private ArrayList<NPC> npcs;
	public ArrayList<Item> items; // we should change this to a List of items later
	public Player player;
	private World world;
	private FloorTile floor;
	private WallTile wall;
	private PriorityQueue graphicsQueue;

	public Map(String mapName, Player p){
		player = p;
		items = new ArrayList<Item>();
		this.world = World.getInstance();
		floor = new FloorTile();
		wall = new WallTile();
		npcs = new ArrayList<NPC>();
		graphicsQueue = new PriorityQueue<Person>();
		parse(mapName);
	}
	
	public ArrayList<NPC> getNPCs() {
		return npcs;
	}

	public void movePlayer(int dir) {
		switch (dir) {
		case 1 :
			if (player.getX() + 1 < fgGrid.length && fgGrid[player.getX() + 1][player.getY()].empty) {
				
				player.move(dir);
				for (Item item : items){
					if (player.getX() == item.col && player.getY() == item.row){
						item.activate();
					}
				}
			}
			if(!player.getCurrentAnimation().getName().equals("RIGHT"))
			{
				player.setCurrentAnimation("RIGHT");
				player.getCurrentAnimation().start();
				player.setFacing(1);
			}
			break;
		case 2 :
			if (player.getY() - 1 >= 0 && fgGrid[player.getX()][player.getY() - 1].empty) {
				
				player.move(dir);
				for (Item item : items){
					if (player.getX() == item.col && player.getY() == item.row){
						item.activate();
					}
				}
			}
			if(!player.getCurrentAnimation().getName().equals("UP"))
			{
				player.setCurrentAnimation("UP");
				player.getCurrentAnimation().start();
				player.setFacing(2);
			}
			break;
		case 3 :
			if (player.getX() - 1 >= 0 && fgGrid[player.getX() - 1][player.getY()].empty) {
				player.move(dir);
				for (Item item : items){
					if (player.getX() == item.col && player.getY() == item.row){
						item.activate();
					}
				}
			}
			if(!player.getCurrentAnimation().getName().equals("LEFT"))
			{
				player.setCurrentAnimation("LEFT");
				player.getCurrentAnimation().start();
				player.setFacing(3);
			}
			break;
		case 4 :
			if (player.getY() + 1 < fgGrid[player.getX()].length && fgGrid[player.getX()][player.getY() + 1].empty) {
				
				player.move(dir);
				for (Item item : items){
					if (player.getX() == item.col && player.getY() == item.row){
						item.activate();
					}
				}
			}
			if(!player.getCurrentAnimation().getName().equals("DOWN"))
			{
				player.setCurrentAnimation("DOWN");
				player.getCurrentAnimation().start();
				player.setFacing(4);
			}
			break;
		}
	}

	public void reset(){
		//items = new ArrayList<Item>();
		npcs = new ArrayList<NPC>();
	}
	
	public int getWidth(){
		return cols;
	}
	public int getHeight(){
		return rows;
	}

	private void parse(String mapName) {
		try{
			BufferedReader br = new BufferedReader(new FileReader(mapName));
			ArrayList<String> bgLines = new ArrayList<String>(),
					fgLines = new ArrayList<String>(),
					itemLines = new ArrayList<String>();
			String line = "";
			int currentList = 0;
			while ((line = br.readLine()) != null) {
				if (line.equals("")) {
					currentList++;
				}
				else {
					switch (currentList) {
					case 0 :
						bgLines.add(line);
						break;
					case 1 :
						fgLines.add(line);
						break;
					case 2 :
						itemLines.add(line);
					}
				}
			}
			bgGrid = new BackgroundTile[bgLines.get(0).length()][bgLines.size()];
			cols = bgGrid.length;
			rows = bgGrid[0].length;
			for (int y = 0; y < bgLines.size(); y++) {
				char[] tiles = bgLines.get(y).toCharArray();
				for (int x = 0; x < bgLines.get(0).length(); x++) {
					switch (tiles[x]) {
					case 'g' :
						bgGrid[x][y] = new BackgroundTile(x, y, OurApplet.grass);
						break;
					case 'h' :
						bgGrid[x][y] = new BackgroundTile(x, y, OurApplet.darkGrass);
						break;
					case 'd' :
						bgGrid[x][y] = new BackgroundTile(x, y, OurApplet.dirt);
						break;
					case 'f' :
						bgGrid[x][y] = new BackgroundTile(x, y, OurApplet.flower);
						break;
					case 'e' :
						bgGrid[x][y] = new BackgroundTile(x, y, OurApplet.darkFlower);
						break;
					case 'w' :
						bgGrid[x][y] = new BackgroundTile(x, y, OurApplet.water);
						break;
					case 'b' :
						bgGrid[x][y] = new BackgroundTile(x, y, OurApplet.brick);
						break;
					case '/' :
						bgGrid[x][y] = new BackgroundTile(x, y, OurApplet.blacktile);
						break;
					case '\\' :
						bgGrid[x][y] = new BackgroundTile(x, y, OurApplet.whitetile);
						break;
					case 'm':
						bgGrid[x][y] = new BackgroundTile(x, y, OurApplet.mountaintile);
						break;
					case 'x':
						bgGrid[x][y] = new BackgroundTile(x, y, OurApplet.rightcornertile);
						break;
					case 'z':
						bgGrid[x][y] = new BackgroundTile(x, y, OurApplet.leftcornertile);
						break;
					case 's':
						bgGrid[x][y] = new BackgroundTile(x, y, OurApplet.skytile);
						break;
					case 'a':
						bgGrid[x][y] = new BackgroundTile(x, y, OurApplet.stairtile);
						break;
					case 'l':
						bgGrid[x][y] = new BackgroundTile(x, y, OurApplet.walltile);
						break;
					case '-':
						bgGrid[x][y] = new BackgroundTile(x, y, OurApplet.bridge);
						break;
					}
				}
			}
			fgGrid = new Tile[fgLines.get(0).length()][fgLines.size()];
			for (int y = 0; y < fgLines.size(); y++) {
				char[] tiles = fgLines.get(y).toCharArray();
				for (int x = 0; x < fgLines.get(0).length(); x++) {
					switch (tiles[x]) {
					case 'x' :
						fgGrid[x][y] = new WallTile();
						break;
					case 'o' :
						fgGrid[x][y] = new FloorTile();
						break;
					case 't' :
						fgGrid[x][y] = new WallTile(OurApplet.tree, x, y);
						break;
					case 'q' :
						fgGrid[x][y] = new WallTile(OurApplet.darkTree, x, y);
						break;
					case 's' :
						fgGrid[x][y] = new WallTile(OurApplet.skinnytree, x, y);
						break;
					case 'r' :
						fgGrid[x][y] = new WallTile(OurApplet.trimmedtree, x, y);
						break;
					case 'w' :
						fgGrid[x][y] = new WallTile(OurApplet.wall, x, y);
						break;
					case '1' :
						fgGrid[x][y] = new WallTile(new Animation(new ImageIcon[] {new ImageIcon("Images/BridgeBroken1.png")}, false), x, y);
						break;
					case '2' :
						fgGrid[x][y] = new WallTile(new Animation(new ImageIcon[] {new ImageIcon("Images/BridgeBroken2.png")}, false), x, y);
						break;
					case '3' :
						fgGrid[x][y] = new WallTile(new Animation(new ImageIcon[] {new ImageIcon("Images/BridgeBroken3.png")}, false), x, y);
						break;
					}
				}
			}
			for (int y = 0; y < itemLines.size(); y++) {
				String[] params = itemLines.get(y).split("_");
					if (params[0].equals("portal")) {
						items.add(new Portal(Integer.parseInt(params[1]), Integer.parseInt(params[2]), params[3], Integer.parseInt(params[4]), Integer.parseInt(params[5]), player));
					}
					else if (params[0].equals("sign")) {
						npcs.add(new Sign(Integer.parseInt(params[1]), Integer.parseInt(params[2]), params[3]));
					}
					else if (params[0].equals("solonman")) {
						npcs.add(new SolonMan(Integer.parseInt(params[1]), Integer.parseInt(params[2]), params[3]));
					}
					else if (params[0].equals("solonmanstationary")) {
						npcs.add(new SolonManStationary(Integer.parseInt(params[1]), Integer.parseInt(params[2]), params[3]));
					}
					else if (params[0].equals("tent"))
					{
						items.add(new Tent(Integer.parseInt(params[1]), Integer.parseInt(params[2])));
					}
					else if (params[0].equals("cart"))
					{
						items.add(new Cart(Integer.parseInt(params[1]), Integer.parseInt(params[2])));
					}
					else if (params[0].equals("solonhouse"))
					{
						items.add(new SolonHouse(Integer.parseInt(params[1]), Integer.parseInt(params[2])));
					}
					else if (params[0].equals("parthenon"))
					{
						items.add(new Parthenon(Integer.parseInt(params[1]), Integer.parseInt(params[2])));
					}
					else if (params[0].equals("fountain"))
					{
						items.add(new Fountain(Integer.parseInt(params[1]), Integer.parseInt(params[2])));
					}
					else if (params[0].equals("pot"))
					{
						items.add(new Pot(Integer.parseInt(params[1]), Integer.parseInt(params[2])));
					}
					else if (params[0].equals("mailbox"))
					{
						items.add(new MailBox(Integer.parseInt(params[1]), Integer.parseInt(params[2])));
					}
					else if (params[0].equals("monk"))
					{
						npcs.add(new Monk(Integer.parseInt(params[1]), Integer.parseInt(params[2]), params[3]));
					}
					else if (params[0].equals("monkhouse"))
					{
						items.add(new MonkHouse(Integer.parseInt(params[1]), Integer.parseInt(params[2])));
					}
					else if (params[0].equals("sphinx"))
					{
						items.add(new Sphinx(Integer.parseInt(params[1]), Integer.parseInt(params[2])));
					}
					else if (params[0].equals("closedsolonhouse"))
					{
						items.add(new ClosedSolonHouse(Integer.parseInt(params[1]), Integer.parseInt(params[2])));
					}
			}
		}
		catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		catch (IOException e) {
			System.out.println("File read error");
		}
	}

	@Override
	public void draw(Graphics g) {
		Object o;
		for (int i = player.getX()-9; i < player.getX()+10; i++){
			for (int j = player.getY()-9; j < player.getY()+10; j++){
				bgGrid[i][j].draw(g);
				if(fgGrid[i][j] instanceof WallTile)
				graphicsQueue.add(fgGrid[i][j]);
			}
		}
		for (NPC n : npcs){
			graphicsQueue.add(n);
		}
		graphicsQueue.add(player);
		for (Item item : items){
			if (item != null) item.draw(g);
		}
		while (graphicsQueue.peek() != null) {
			if ((o = graphicsQueue.poll()) instanceof Person) {
				((Person)o).draw(g);
			}
			else if ((o instanceof WallTile))
				((WallTile)o).draw(g);
		}
	}
	
	public BackgroundTile[][] getGrid(){
		return bgGrid;
	}
}
